package com.siyoumi.service.wx_center;

import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson.JSON;
import com.siyoumi.component.LogPipeLine;
import com.siyoumi.component.XRedis;
import com.siyoumi.component.http.InputData;
import com.siyoumi.component.http.XHttpContext;
import com.siyoumi.config.SysConfig;
import com.siyoumi.entity.SysAccsuperConfig;
import com.siyoumi.entity.SysAccsuperConfigService;
import com.siyoumi.service.wx_center.common_handle.*;
import com.siyoumi.util.XDate;
import com.siyoumi.util.XReturn;
import com.siyoumi.util.XStr;
import com.siyoumi.validator.XValidator;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 公众号回复处理
 * 文本回复主处理方法
 */
@Slf4j
public class CenterHandler {
    @Getter
    @Setter
    SysAccsuperConfig entityConfig;

    @Setter
    private Boolean fromTask = false; //任务执行


    public static CenterHandler getInstance(String x) {
        SysAccsuperConfig entityConfig = SysAccsuperConfigService.getBean().getXConfig(x, true);
        CenterHandler app;

        if (entityConfig.wx()) {
            if (entityConfig.wxOpen()) {
                log.debug("公众号授权模式");
                app = new CenterHandlerClient();
            } else {
                log.debug("公众号");
                app = new CenterHandler();
            }
        } else if (entityConfig.wxApp()) {
            log.debug("小程序");
            app = new CenterHandler();
        } else {
            log.debug("企业微信");
            app = new CenterHandlerCorp();
        }

        app.setEntityConfig(entityConfig);

        return app;
    }


    /**
     * 处理队列key
     *
     * @param openid
     */
    static public String addHandleQueueKey(String openid) {
        //Integer num = XStr.funcToAsciiNum(openid);
        Integer num = 1;
        Integer taskTotal = 1; //比如运行3个任务
        if (SysConfig.getIns().isDev()) {
            taskTotal = 2;
        }

        Integer taskIndex = num % taskTotal;
        log.debug("{} % {} = {}", num, taskTotal, taskIndex);
        return addHandleQueueKey(taskIndex);
    }

    static public String addHandleQueueKey(Integer taskIndex) {
        return XStr.format("center_handle:{0}", taskIndex.toString());
    }

    /**
     * 进处理队列
     *
     * @param data
     */
    static public void addHandleQueue(CenterHandlerData data) {
        String key = addHandleQueueKey(data.getOpenid());

        Map<String, String> mapData = new HashMap<>();
        mapData.put("site_id", data.getX());
        mapData.put("openid", data.getOpenid());
        mapData.put("strXml", data.getStrXml());
        mapData.put("url", XHttpContext.getUrlPath());
        mapData.put("t", XDate.toDateTimeString());

        XRedis.getBean().lPush(key, JSON.toJSONString(mapData));
    }

    /**
     * 检查签名
     */
    public String checkSign() {
        if (!"get".equalsIgnoreCase(XHttpContext.getHttpServletRequest().getMethod())) {
            return null;
        }

        InputData inputData = InputData.fromRequest();

        String timestamp = inputData.input("timestamp");
        String nonce = inputData.input("nonce");
        String signature = inputData.input("signature");
        String echostr = inputData.input("echostr");
        if (XStr.isNullOrEmpty(signature)) {
            XValidator.err(20039, "miss signature");
        }

        String token = getEntityConfig().getAconfig_token();

        String[] ss = new String[]{token, timestamp, nonce};
        String str1_sign = getSign(ss);

        if (!str1_sign.equals(signature)) {
            String errmsg = "签名失败 , " + str1_sign + " != " + signature;
            XValidator.err(50069, errmsg);
        }

        return echostr;
    }

    public void handle(CenterHandlerData data) {
        CenterHandlerContext ctx = new CenterHandlerContext();
        ctx.setFromTask(this.fromTask);
        ctx.setHandleData(data);
        ctx.setEntityConfig(getEntityConfig());

        LogPipeLine.of().setLogMsgFormat("content: {0}", ctx.getContent());

        Boolean decodeXml = false;
        if (getEntityConfig().wxOpen()) {
            LogPipeLine.of().setLogMsg("公众号授权模式，需要解密内容");
            decodeXml = true;
        }
        if (getEntityConfig().corp()) {
            log.info("企业微信，需要解密内容");
            decodeXml = true;
        }
        if (decodeXml) {
            ctx.addLastHandle(new CenterHandleDecXmlAndCheckSign());
        }

        ctx.addLastHandle(new CenterHandleIgnoreMsgType());
        ctx.addLastHandle(new CenterHandleEvent());
        ctx.addLastHandle(new CenterHandleWordtrans());
        ctx.addLastHandle(new CenterHandleApp());

        while (true) {
            if (ctx.getHandles().size() <= 0) {
                break;
            }
            ICenterHandle handle = ctx.getHandles().get(0);
            LogPipeLine.of().setLogMsgFormat("{0}---BEGIN", handle.getClass().getSimpleName());

            handle.handle(ctx);
            LogPipeLine.of().setLogMsgFormat("{0}---END", handle.getClass().getSimpleName());
            if (ctx.isFinal()) {
                LogPipeLine.of().setLogMsgFormat("{0}---中断", handle.getClass().getSimpleName());
                break;
            }

            ctx.getHandles().remove(handle);
        }

        if (ctx.doDiglog()) {
            //最后记录日志
            LogPipeLine.of().setLogMsgFormat("记录日志dialog");
            CenterHandleDialog handleDialog = new CenterHandleDialog();
            handleDialog.handle(ctx);
        }
    }


    /**
     * 获取签名
     *
     * @param ss
     */
    static public String getSign(String[] ss) {
        Arrays.sort(ss);
        String str1 = String.join("", ss);
        log.debug("str1: {}", str1);
        return DigestUtil.sha1Hex(str1);
    }

    /**
     * 根据appid，处理
     *
     * @param appId
     * @param ctx
     */
    static public XReturn handleByAppId(String appId, CenterHandlerContext ctx) {
        ICenterHandle handle = getHandleByAppId(appId);
        if (handle != null) {
            return handle.handle(ctx);
        }

        return null;
    }

    /**
     * 根据应用，应用相关处理
     *
     * @param appId
     */
    @SneakyThrows
    static public ICenterHandle getHandleByAppId(String appId) {
        //LogPipeLine.getTl().setLogMsgFormat("app_id: {0}", appId);
        if (XStr.isNullOrEmpty(appId)) {
            return null;
        }

        String className = XStr.lineToHump(appId);
        className = XStr.toUpperCase1(className + "Wx");
        String classPackage = XStr.concat("xiaobo.z_app.", appId, ".a_service.", className);

        //LogPipeLine.getTl().setLogMsgFormat("className: {0}", className);
        log.info("classPackage: {}", classPackage);

        Class<?> clazz = null;
        try {
            clazz = Class.forName(classPackage);
        } catch (ClassNotFoundException ex) {
            log.warn("未找到处理类");
        }

        if (clazz == null) {
            return null;
        }
        return (ICenterHandle) clazz.newInstance();
    }
    
    @SneakyThrows
    public String decryptTxt(String encTxt) {
        String key = getEntityConfig().getAconfig_key();

        String txt = "";
        byte[] original;
        try {
            byte[] aesKey = Base64.decodeBase64(key + "=");

            // 设置解密模式为AES的CBC模式
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
            IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
            cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);

            // 使用BASE64对密文进行解码
            byte[] encrypted = Base64.decodeBase64(encTxt);

            // 解密
            original = cipher.doFinal(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }

        String fromAppId;
        try {
            // 去除补位字符
            byte[] bytes = PKCS7Encoder.decode(original);

            //获取内容长度
            byte[] xmlLenByte = Arrays.copyOfRange(bytes, 16, 20);
            int xmlLength = corpByteToInt(xmlLenByte);

            txt = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), StandardCharsets.UTF_8);
            fromAppId = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }

        // receiveid不相同的情况
        if (!fromAppId.equals(getEntityConfig().getAconfig_app_id())) {
            XValidator.err(50302, XStr.format("aes解密失败, {0}, {1}", fromAppId, getEntityConfig().getAconfig_app_id()));
        }

        return txt;
    }

    /**
     * 还原4个字节的网络字节序
     *
     * @param orderBytes
     */
    static public int corpByteToInt(byte[] orderBytes) {
        int sourceNumber = 0;
        for (int i = 0; i < 4; i++) {
            sourceNumber <<= 8;
            sourceNumber |= orderBytes[i] & 0xff;
        }
        return sourceNumber;
    }
}

